#pragma once

#include <stdio.h>
#include <string>

namespace builder {
    
/// @brief 产品 - 包含多个组成部件的复杂对象。
class Product {
public:
    void Show() {
        printf("Show Product ...\n");
    }

private:
    std::string partA_;
    std::string partB_;
    std::string partC_;
};

/// @brief 抽象建造者 - 包含创建产品各个子部件的抽象方法
class AbstractBuilder {
public:
    AbstractBuilder() {
        product_.reset(new Product());
    }
    Product* GetResult() {
        return product_.get();
    }

    virtual void BuilderPartA() = 0;
    virtual void BuilderPartB() = 0;
    virtual void BuilderPartC() = 0;

protected:
    std::shared_ptr<Product> product_;
};

/// @brief 具体建造者 - 实现了抽象建造者接口
class ConcreteBuilder : public AbstractBuilder {
public:
    virtual void BuilderPartA() {
        printf("Builder PartA...\n");
    }
    virtual void BuilderPartB() {
        printf("Builder PartB...\n");
    }
    virtual void BuilderPartC() {
        printf("Builder PartC...\n");
    }
};

/// @brief 指挥者 - 调用建造者中的方法完成复杂对象的创建
class Director {
public:
    Director(AbstractBuilder* builder) : builder_(builder) {}
    Product* ConstructProduct() {
        builder_->BuilderPartA();
        builder_->BuilderPartB();
        builder_->BuilderPartC();
        return builder_->GetResult();
    }

private:
    AbstractBuilder* builder_;
};

} // namespace builder

void Test_05_builder_impl_1() {
    printf("-------------------- %s --------------------\n", __FUNCTION__);
    std::shared_ptr<builder::AbstractBuilder> builder(new builder::ConcreteBuilder());
    std::shared_ptr<builder::Director> director(new builder::Director(builder.get()));

    builder::Product* ptr = director->ConstructProduct();
    ptr->Show();
}

// -------------------- Test_05_builder_impl_1 --------------------
// Builder PartA...
// Builder PartB...
// Builder PartC...
// Show Product ...